from app.libs.enums import ClientTypeEnum
from app.libs.error_code import Success, DeleteSuccess
from app.libs.redprint import Redprint
from flask import request, jsonify, g
from app.forms.user import ClientForm, UserEmailForm
from app.models.base import db
from app.models.user import User
from app.libs.token_auth import auth

red_user = Redprint('user')


@red_user.route('/register', methods=['POST'])
def create_clent():
    ''' 把不同的注册放在同一个api中真的好吗,其实这样可以少写很多的代码,而且一个网站只有一个注册接口,是比较标准的
        分开的话,会让逻辑简单,但函数增多,HTTP请求增多.'''
    form = ClientForm(request.json)
    form.validate_for_api()
    can_register = {
        ClientTypeEnum.USER_EMAIL: __register_user_by_email
    }
    can_register[form.type.data]()
    return Success()


@red_user.route('/user/<int:uid>', methods=['GET'])
@auth.login_required # TODO 它是怎么导向veriry_password验证器的?
def get_user(uid):
    ''' 这里直接返回user对象可能是因为刚好够用,或者前段处理数据更方便
        但如果需要的数据比较复杂,涉及的模型类较多,这种直接返回user
        的方式非常不可取,就需要灵活使用view_model层来处理数据'''
    user = User.query.filter_by(id=uid).first_or_404()
    return jsonify(user)


@red_user.route('/delete/<int:uid>', methods=['DELETE'])
@auth.login_required
def delete_user(uid):
    ''' 逻辑漏洞1:删除接口如果有人一直请求,不能一直返回删除成功
        所以对于被删除的数据,查询完是否有值要做一个逻辑判断
        逻辑漏洞2:这种url参数可以被用户自己修改的情况,可能会出现超权的情况
        所以在这种删除敏感信息的api中,我们需要更加安全的做法'''
    uid = g.user.uid # user里保存了user_info这个对象
    with db.auto_commit():
        user = User.query.filter_by(id=uid).first_or_404()
        user.delete()
    return DeleteSuccess()


def __register_user_by_email():
    # 创建一个新的用户对象
    form = UserEmailForm(data=request.json)
    # TODO 这里的参数验证失败,返回error应该怎么做? 前后端分离的情况下呢?
    # 重写Form对象,直接抛出异常给到前端
    form.validate_for_api()
    # TODO 如果这里创建用户失败了呢?只是抛出异常吗? 不给一些友好的提示吗?
    # 这里使用自定义的异常类就可以解决,返回的还是json对象,抛异常的同时将错误信息返回给前段,让前段输出错误的提示.
    User.create_user(form.nickname.data, form.account.data, form.secret.data)